﻿using Newtonsoft.Json;
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace Zeus.HttpPower
{
    public class ZHPClient
    {
        public const long TicksPerSecond = 10000000;

        public const long TicksPerMillisecond = 10000;

        public const string JsonMediaType = "application/json";

        private HttpClient _client;

        private void OnDefaultBeginRequest(ZHPContext zHPContext)
        {
            Console.WriteLine($"{zHPContext.GuidRequest.ToString("N")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} Request To {zHPContext.UriInfo.ToString()} JSON DATA:\r\n{JsonConvert.SerializeObject(zHPContext.RequestBody)}");
        }

        private void OnDefaultEndRequest(ZHPContext zHPContext)
        {
            Console.WriteLine($"{zHPContext.GuidRequest.ToString("N")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} Get Response Exect Time{zHPContext.Stopwatcher.ElapsedMilliseconds} ms JSON DATA:\r\n{zHPContext.ResponseBody}");
        }

        private void OnDefaultException(ZHPContext zHPContext)
        {
            Console.WriteLine($"{zHPContext.GuidRequest.ToString("N")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} Has Exception!{zHPContext.Stopwatcher.ElapsedMilliseconds} ms Exception DATA:\r\n{JsonConvert.SerializeObject(zHPContext.ExceptionInfo)}");
        }

        public ZHPClient(int seconds = 30)
        {
            _onBeginRequest = new Action<ZHPContext>(OnDefaultBeginRequest);
            _onEndRequest = new Action<ZHPContext>(OnDefaultEndRequest);
            _onException = new Action<ZHPContext>(OnDefaultException);
            ClientInit(seconds);
        }

        public ZHPClient(Action<ZHPContext> onBeginRequest, Action<ZHPContext> onEndRequest, Action<ZHPContext> onException, int seconds = 30)
        {
            _onBeginRequest = new Action<ZHPContext>(onBeginRequest ?? OnDefaultBeginRequest);
            _onEndRequest = new Action<ZHPContext>(onEndRequest ?? OnDefaultEndRequest);
            _onException = new Action<ZHPContext>(onException ?? OnDefaultException);
            ClientInit(seconds);
        }

        private Action<ZHPContext> _onBeginRequest;
        private Action<ZHPContext> _onEndRequest;
        private Action<ZHPContext> _onException;


        private void ClientInit(int seconds)
        {
            _client = new HttpClient();
            _client.Timeout = new TimeSpan(0, 0, seconds);
        }

        /// <summary>
        /// Post
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="uri"></param>
        /// <param name="dataJson"></param>
        /// <param name="timeTicks"></param>
        /// <returns></returns>
        public async Task<ZeusResponse<T>> ZeusRequestPost<T>(Uri uri, object dataJson, Dictionary<string, string> headers = null)
        {
            var context = new ZHPContext()
            {
                EncodingInfo = Encoding.UTF8,
                GuidRequest = Guid.NewGuid(),
                MediaType = JsonMediaType,
                RequestBody = JsonConvert.SerializeObject(dataJson),
                Stopwatcher = new Stopwatch(),
                UriInfo = uri
            };

            var content = new StringContent(context.RequestBody, context.EncodingInfo, context.MediaType);

            if (headers != null)
            {
                foreach (var item in headers)
                {
                    content.Headers.Add(item.Key, item.Value);
                }
            }

            _onBeginRequest(context);
            context.Stopwatcher.Start();
            try
            {
                var responseMessage = await _client.PostAsync(context.UriInfo, content);
                if (responseMessage.StatusCode != HttpStatusCode.OK)
                {
                    throw new Exception($"HTTP Request Error! Status:{responseMessage.StatusCode}");
                }
                context.ResponseBody = await responseMessage.Content.ReadAsStringAsync();
                _onEndRequest(context);
                context.Stopwatcher.Stop();
                return JsonConvert.DeserializeObject<ZeusResponse<T>>(context.ResponseBody);
            }
            catch (Exception ex)
            {
                context.ExceptionInfo = ex;
                _onException(context);
                context.Stopwatcher.Stop();
                throw ex;
            }
        }

        public async Task<T> Post<T>(Uri uri, object dataJson)
        {
            ServicePointManager.DefaultConnectionLimit = 512;

            var content = new StringContent(JsonConvert.SerializeObject(dataJson), Encoding.UTF8, JsonMediaType);

            var responseMessage = await _client.PostAsync(uri.ToString(), content);
            if (responseMessage.StatusCode != HttpStatusCode.OK)
            {
                throw new Exception($"HTTP Request Error! Status:{responseMessage.StatusCode}");
            }
            var jsonResult = await responseMessage.Content.ReadAsStringAsync();
            return JsonConvert.DeserializeObject<T>(jsonResult);

        }

    }
}
